<?php
use frontend\modules\yii2\widgets\layouts\markdown\Markdown;

$this->title = '邮件的配置和使用教程-mailer-Components组件';
$this->registerMetaTag([
    'name' => 'keywords',
    'content' => 'yii,yii2,框架,应用组件,Components,使用,教程,邮件,mailer,email,mail'
]);
$this->registerMetaTag([
    'name' => 'description',
    'content' => 'Yii内置的邮件组件可以方便地实现发送邮件功能，但是您必须保证邮件服务器是允许客户端发送邮件的。'
]);


$html = [
    "概述" => <<<HTML
# 邮件的配置和使用教程
Yii内置的邮件组件可以方便地实现发送邮件功能，但是您必须保证邮件服务器是允许客户端发送邮件的。在国内，常见的免费邮箱有QQ邮箱、163邮箱、新浪邮箱等。在本节中，我们介绍如何使用QQ邮件服务器实现发送邮件的功能。

HTML,
    "重要概念" => <<<HTML
## 重要概念 id=compose
先来看一个发送邮件的通用实例：
```php
Yii::\$app->mailer->compose()
    ->setTo("log@qq.com") // 接收邮件的邮箱
    ->setSubject("email sending test") // 邮件主题
    ->setTextBody("Hello World") // 邮件内容
    ->send();
```
上述代码很直观，除了`compose()`外其他的设置都应该很好理解，本节所谓的重要概念其实就是对它进行讲解。

`compose()`返回一个消息实例，通过这个方法可以使用消息模板，我们可以把它理解为控制器中渲染视图的`render()`方法，它有默认的layout页面（`/common/mail/layouts/`目录下），通过传入的邮件不同格式而分为html和text：
```php
    /**
     * @var string|bool HTML layout view name. This is the layout used to render HTML mail body.
     * The property can take the following values:
     *
     * - a relative view name: a view file relative to [[viewPath]], e.g., 'layouts/html'.
     * - a [path alias](guide:concept-aliases): an absolute view file path specified as a path alias, e.g., '@app/mail/html'.
     * - a boolean false: the layout is disabled.
     */
    public \$htmlLayout = 'layouts/html';
    /**
     * @var string|bool text layout view name. This is the layout used to render TEXT mail body.
     * Please refer to [[htmlLayout]] for possible values that this property can take.
     */
    public \$textLayout = 'layouts/text';
    /**
```
举个例子：
```php
// 启用'layouts/html'
Yii::\$app->mailer->compose(["html" => "emailVerify-html.php"])

// 启用'layouts/text'
Yii::\$app->mailer->compose(["text" => "emailVerify-text.php"])
```
由上述代码可知，`compose()`的第一个参数就是指定邮件内容模板，我们也可以自定义模板，请看[发送图片](#image)一节。

`compose()`的第二个参数是传入邮件内容模板的参数，从而可以改变邮件的内容：
```php
Yii::\$app->mailer
    ->compose(
        ['html' => 'emailVerify-html'],
        ['user' => \$user]
    )
    ->setTo("lvzmen@qq.com")
    ->setSubject("email subject")
    ->send();
```
熟悉`composer()`的参数很重要，因为下面要介绍的所有发送邮件的功能都需要依赖它创建出来的消息实例。

HTML,
    "前提" => <<<HTML
## 开启QQ客户端发送功能 id=prepare
要启用QQ邮箱的客户端发送邮件功能，需要注意两点：
- 开启smtp服务：
![开启QQ的smtp服务](/images/20211230222602.png "开启QQ的smtp服务")

- 申请授权码：  
这个授权码需要当做密码使用，你不能将邮箱的登录密码当做客户端的邮件发送密码，而是要申请授权码。
HTML,
    "CONFIG" => <<<HTML
## 邮件组件配置举例 id=config
下面是QQ邮箱的配置：
```php
'components' => [
    'mailer' => [
        'class' => 'yii\swiftmailer\Mailer',
        'viewPath' => '@common/mail',
        'transport' => [
            'class' => 'Swift_SmtpTransport',
            'host' => 'smtp.qq.com',
            'username' => 'log@qq.com',
            'password' => 'xxxxxxxxxxxxx', // 此处填写QQ授权码
            'port' => '465',
            'encryption' => 'ssl',
        ],
        'messageConfig' => [
            'charset' => 'UTF-8',
            // 这里的from必须要和上述username保持一致
            'from' => ['log@qq.com' => 'Yii'],
        ],
    ],
],
```
> 在配置邮箱和`EmailTarget`的时候，值得注意的是`from`属性需要和邮箱组件中的`username`属性保持一致，否则无法发送邮件。

HTML,

    "send" => <<<HTML
## 发送文本邮件 id=send-text
有了上述配置后，您可以尝试发送文本类型的邮件，如下所示：
```php
Yii::\$app->mailer->compose()
    ->setTo("log@qq.com") // 接收邮件的邮箱
    ->setSubject("email sending test") // 邮件主题
    ->setTextBody("Hello World") // 邮件内容
    ->send();
```
HTML,
    "send.html" => <<<HTML
## 发送html邮件 id=send-html
虽然说文本格式的邮件可以满足大部分的要求，但是文本邮件缺少了内容表达的效果，如：表格、图片、字体颜色等。为了弥补文本邮件的缺陷，Yii提供了HTML格式的邮件发送功能。

既然是html格式的邮件，那邮件本身应该是一张网页，为了减少重复代码，Yii在`common/mail/layouts/html.php`中封装网页公共的部分。发送html邮件的举例如下：
```php
Yii::\$app->mailer
    ->compose(
        ['html' => 'emailVerify-html'],
        ['user' => \$user]
    )
    ->setTo(\$this->email)
    ->setSubject('Account registration at ' . Yii::\$app->name)
    ->send();
````
上述代码是发送html邮件的例子，其中`emailVerify-html`是定义在`common/mail/`下的视图文件，而`\$user`是传入视图文件的参数，视图文件内容如下：
```html
use yii\helpers\Html;

/* @var \$this yii\web\View */
/* @var \$user common\models\User */

\$verifyLink = Yii::\$app->urlManager->createAbsoluteUrl(['site/verify-email', 'token' => \$user->verification_token]);
?>
<div class="verify-email">
    <p>Hello <?= Html::encode(\$user->username) ?>,</p>

    <p>Follow the link below to verify your email:</p>

    <p><?= Html::a(Html::encode(\$verifyLink), \$verifyLink) ?></p>
</div>
```
HTML,
    "发送日志邮件" => <<<HTML
## 发送日志邮件 id=log
[发送日志邮件](/docs/components/log/email)是日志组件的一个子功能，要使用这个功能需要配置`yii\log\EmailTarget`，如下：
```php
[
  'components' => [
      'log' => [
          'flushInterval' => 1,
          'traceLevel' => 0,
          'targets' => [
              "email_target" => [
                  'logVars' => [],
                  'class' => 'yii\log\EmailTarget',
                  'mailer' => 'mailer', // 邮箱组件的components id
                  'categories' => ['email'],
                  'message' => [
                      // 这里的from必须要和邮箱组件的username保持一致
                      'from' => ['log@qq.com'],
                      'to' => ['developer1@example.com', 'developer2@example.com'],
                      'subject' => 'Log message',
                  ],
              ],
          ],
      ],
  ],
]
```
此时我们就可以很方便地发送邮件了：
```php
Yii::info("Send email test", "email");
```
不过这个方式有个弊端：接受方是固定的，需要在log组件中指定。如果需要修改目标地址，可以参考如下代码：
```php
Yii::\$app->log->targets["email_target"]->message["to"] = ["new_receiver@qq.com"];
Yii::info("email message test", "email");
```
HTML,
    "attach" => <<<HTML
## 发送附件 id=attachment
能够发送附件是邮件的基础功能，`mailer`组件也同样提供了这个功能，举例如下：
```php
Yii::\$app->mailer->compose()
    ->setTo("test@qq.com")
    ->setSubject("test")
    ->setTextBody("send attachment")
    ->attach('images/picture.png')
    ->send();
```
> 注意：attach默认从`frontend/web/`下查找文件，如果您设置为`/images/xxx.png`则无法找到路径。

HTML,
    "send.image" => <<<HTML
## 发送图片 id=image
邮件中包含图片是非常常见的情况，Yii自然也支持这个功能，主要的思路是在html格式邮件中用`img`标签指定需要发送的图片，图片需要公网可以访问的完整url地址，下面介绍用法：
1. 在`/common/mail/`下新建`image.php`文件；
2. 在`image.php`文件中写入如下代码：
```html
<style>
    /*给图片添加样式*/
    img {
        border: 1px solid #ccc;
        box-shadow: rgb(0 0 0) 0 0 8px;
        width: 30%;
    }
</style>
<!--http://127.0.0.1:20080/images/20211109180257.png-->
<img src="<?=Yii::\$app->request->hostInfo?>/images/yii.png"/>
```
3. 使用html模板发送邮件：
```php
Yii::\$app->mailer
    ->compose(["html" => "image"])
    ->setSubject("send images test")
    ->setTo("lvzmen@qq.com")
    ->send();
```

发送结果如下：  
![发送带图片的邮件截图](/images/20220104152013.png "发送带图片的邮件截图")

> 注意：由于图片的url是本地`127.0.0.1`的地址，因此在本地电脑打开邮箱才能看到图片，在测试和生产环境应该调整为可以访问到图片的域名或ip。

HTML,
    "" => <<<HTML

HTML,
];

//Yii::$app->log->targets["email_target"]->message["to"] = ["chenzw@yankon.com","2462238234@qq.com"];
//Yii::info("email message test", "email");die;

//Yii::$app->mailer
//    ->compose(["html" => "image"])
//    ->setSubject("send images test")
//    ->setTo("2462238234@qq.com")
//    ->send();
//
//die;


//Yii::$app->mailer->compose()
//    ->setTo("2462238234@qq.com")
//    ->setSubject("test")
//    ->setTextBody("send attachment")
//    ->attach('images/20211109180257.png')
//    ->send();die;

// Yii::info("syslog message test", "syslog");die;
// var_dump(Yii::$app->log->targets["login"]->messages = ["test", "info", "login"]);die;
// die;

echo Markdown::widget(["content" => implode("\n", $html)]);

